/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ania2;

import ania2.engine.utils.ZobristHashTables;
import ania2.enums.Fields;

/**
 *
 * @author pawel
 */
public class BoardPosition {

    private long whitePieces;
    private long blackPieces;
    private long queens;
    private static final long PERMITTED = Long.parseLong("0000011110111111110111111110111111110111100000000000000000000000", 2);
    private int hashCode;
    private long lockCode;

    public BoardPosition() {
    }

    public BoardPosition(long whitePieces, long blackPieces, long queens) {
        this.whitePieces = whitePieces;
        this.blackPieces = blackPieces;
        this.queens = queens;
    }

    public long getBlackPieces() {
        return blackPieces;
    }

    public void setBlackPieces(long blackPieces) {
        this.blackPieces = blackPieces;
    }

    public long getQueens() {
        return queens;
    }

    public void setQueens(long queens) {
        this.queens = queens;
    }

    public long getWhitePieces() {
        return whitePieces;
    }

    public void setWhitePieces(long whitePieces) {
        this.whitePieces = whitePieces;
    }

    public static long getPermitted() {
        return PERMITTED;
    }

    public int getHashCode() {
        return hashCode;
    }

    public void setHashCode(int hashCode) {
        this.hashCode = hashCode;
    }

    public long getLockCode() {
        return lockCode;
    }

    public void setLockCode(long lockCode) {
        this.lockCode = lockCode;
    }

    public void computeHashAndLockCode() {
        long[][] hashRandomTable = ZobristHashTables.HASH_CODE_TABLE;
        long[][] lockRandomTable = ZobristHashTables.LOCK_CODE_TABLE;
        this.hashCode = 0;
        //this.lockCode = 0;
        long white = this.whitePieces & ~queens;
        long black = this.blackPieces & ~queens;
        long whiteQueens = this.whitePieces & queens;
        long blackQueens = this.blackPieces & queens;
        long tmp = Long.highestOneBit(white);
        while (tmp != 0) {
            white ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            hashCode ^= hashRandomTable[index][0];
            //lockCode ^= lockRandomTable[index][0];
            tmp = Long.highestOneBit(white);
        }
        tmp = Long.highestOneBit(black);
        while (tmp != 0) {
            black ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            hashCode ^= hashRandomTable[index][1];
            //lockCode ^= lockRandomTable[index][1];
            tmp = Long.highestOneBit(black);
        }
        tmp = Long.highestOneBit(whiteQueens);
        while (tmp != 0) {
            whiteQueens ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            hashCode ^= hashRandomTable[index][2];
            //lockCode ^= lockRandomTable[index][2];
            tmp = Long.highestOneBit(whiteQueens);
        }
        tmp = Long.highestOneBit(blackQueens);
        while (tmp != 0) {
            blackQueens ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            hashCode ^= hashRandomTable[index][3];
            //lockCode ^= lockRandomTable[index][3];
            tmp = Long.highestOneBit(blackQueens);
        }
        lockCode = (int) (whitePieces + blackPieces + queens);
    }

    @Override
    public int hashCode() {
        return getHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BoardPosition) {
            BoardPosition p = (BoardPosition) obj;
            if (this.getWhitePieces() == p.getWhitePieces() &&
                    this.getBlackPieces() == p.getBlackPieces() &&
                    this.getQueens() == p.getQueens()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        String str = new String("białe: ");
        Fields[] fields = Fields.values();
        long white = whitePieces & ~queens;
        long black = blackPieces & ~queens;
        long whiteQueens = whitePieces & queens;
        long blackQueens = blackPieces & queens;
        long tmp = Long.highestOneBit(white);
        while (tmp != 0) {
            white ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            str += fields[index].toString() + ", ";
            tmp = Long.highestOneBit(white);
        }
        str += "czarne: ";
        tmp = Long.highestOneBit(black);
        while (tmp != 0) {
            black ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            str += fields[index].toString() + ", ";
            tmp = Long.highestOneBit(black);
        }
        str += "białe damki: ";
        tmp = Long.highestOneBit(whiteQueens);
        while (tmp != 0) {
            whiteQueens ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            str += fields[index].toString() + ", ";
            tmp = Long.highestOneBit(whiteQueens);
        }
        str += "czarne damki: ";
        tmp = Long.highestOneBit(blackQueens);
        while (tmp != 0) {
            blackQueens ^= tmp;
            int index = 64 - Long.toBinaryString(tmp).length();
            str += fields[index].toString() + ", ";
            tmp = Long.highestOneBit(blackQueens);
        }
        return str;
    }

    public void setStandardBeginingPosition() {
        this.whitePieces = 0;
        for (int i = 5; i < 9; i++) {
            whitePieces |= (1L << (63 - i));
        }
        for (int i = 10; i < 18; i++) {
            whitePieces |= (1L << (63 - i));
        }
        this.blackPieces = 0;
        for (int i = 28; i < 36; i++) {
            blackPieces |= (1L << (63 - i));
        }
        for (int i = 37; i < 41; i++) {
            blackPieces |= (1L << (63 - i));
        }
        this.queens = 0;
    }
}
